#pragma hdrstop
#pragma package(smart_init)
#include <StdIO.h>

#include "BTrieve.h"

#define MODULE_TAG 110
 HANDLE hBtr = NULL;
BTRCALLFCT CBtrvFile::m_EicBtrCall = NULL;
//*******************************************//
// Macros supplémentaires pour le mode DEBUG //
//*******************************************//
#ifdef _DEBUG
 #define K_UNKNOWN                0xFE
// #define SET_LAST_KEY( eKeyID)    if( (eKeyID) != K_CURRENT) dbgm_eLastKeyID = (eKeyID)
// #define IS_LAST_KEY( eKeyID)     ( dbgm_eLastKeyID == (eKeyID))
// #define ASSERT_LAST_KEY( eKeyID) ASSERT( IS_LAST_KEY( (eKeyID)))
 #define SET_LAST_KEY( eKeyID)
 #define IS_LAST_KEY( eKeyID) true
 #define ASSERT_LAST_KEY( eKeyID)
 #define ASSERT_DUMMY()           ASSERT( *(DWORD*)sm_pvDummy == 0)
 #define ASSERT_FILENAME( strFN)  AssertFileName( (strFN), __LINE__)

 // Vérifie la validité d'un nom de fichier BTrieve (doit être un nom au format 8.3 - sans espace)
 static void __fastcall AssertFileName( const AnsiString& strShortFileName, unsigned long ulNoLigne)
 {
  if( strShortFileName.IsEmpty())
    Assert( ulNoLigne, __FILE__);
  if( strchr( strShortFileName.c_str(), ' '))
    Assert( ulNoLigne, __FILE__);
   if( ( ::GetShortPathName( strShortFileName.c_str(), NULL, 0) - 1) > (DWORD)strShortFileName.Length())
    Assert( ulNoLigne, __FILE__);

  AnsiString strForced83;

  strForced83.SetLength( strShortFileName.Length());

  if( ( ::GetShortPathName( strShortFileName.c_str(), strForced83.c_str(), strForced83.Length() + 1) - 1) > (DWORD)strForced83.Length())
    Assert( ulNoLigne, __FILE__);
  if( strForced83.AnsiCompareIC( strShortFileName))
    Assert( ulNoLigne, __FILE__);
 }
#else
 #define SET_LAST_KEY( eKeyID)
 #define IS_LAST_KEY( eKeyID)
 #define ASSERT_LAST_KEY( eKeyID)
 #define ASSERT_DUMMY()
 #define ASSERT_FILENAME( strFN)
#endif

#if K_UNKNOWN == K_CURRENT
 #error K_UNKNOWN doit avoir une valeur diffrente de K_CURRENT (K_CURRENT permet de spécifier l'option NCC)
#endif


// Désactive la fusion des chaînes dupliquées (car CBtrvFile::sm_pvDummy DOIT avoir 4 caractères de long)
#pragma option push -d-
void* CBtrvFile::sm_pvDummy = "\0\0\0"; // Pour passer des paramètres inutiles
// Restaure la fusion des chaînes dupliquées
#pragma option pop
__fastcall CBtrvFile::CBtrvFile( void)
{
 #if sizeof( m_pos) != POS_BLOCK_SIZE
  #error **** Problème de définition de la position dans un fichier BTrieve ***
 #endif
 m_nSizeOfRecord = m_StatusErreur = 0;
 InitBtrv32();
// SET_LAST_KEY( K_UNKNOWN);
}



__fastcall CBtrvFile::~CBtrvFile( void)
{
 Close( TAG( 10));
}



/*----------------------------------------------------------------------------*\
------------- CBtrvFile::GetNbEnreg() ------------------------------------------
--------------------------------------------------------------------------------
-                                                                              -
-   Cette fonction retourne le nombre d'enregistrements physiques du fichier.  -
\*----------------------------------------------------------------------------*/
DWORD __fastcall CBtrvFile::GetNbEnreg( void)
const
{
 BTRV_FILE_SPEC fs;                          // Structure de description du fichier
 unsigned long  nSizeOf;                     // Taille de la structure
 unsigned       uErrCode;                    // Code erreur
 char           szExtendedFileFileName[ 64]; // Nom du fichier étendu associé

 ASSERT( IsOpened);

 m_StatusErreur = 0;
 ////////////////////////////////////////////////////////////
 // Lecture du nombre d'enregistrements actuels du fichier //
 ////////////////////////////////////////////////////////////
 nSizeOf = sizeof( fs);
 switch( uErrCode = m_EicBtrCall( BTRV_Stat, (void*)m_pos, &fs, &nSizeOf, szExtendedFileFileName, sizeof( szExtendedFileFileName), 0))
 { case BTRVERR_DATA_BUFFER_LENGTH :
   case BTRVERR_SUCCESS            : break;
   default                         : ThrowUserError( TAG( 20), BTRV_Stat, 0, uErrCode);
 }
 return fs.dwNbRecords;
} /* CBtrvFile::GetNbEnreg() */


/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*\
!!!!!!!!!!!!! CBtrvFile::Stop() !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!                                                                              !
!   Cette procédure permet de terminer la session MKDE de la tâche.            !
\*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
void __fastcall CBtrvFile::Stop( void)
{
 if (!m_EicBtrCall)
  return;
 #ifdef _DEBUG
  unsigned uErrCode; // Code erreur
  if( ( uErrCode = m_EicBtrCall( BTRV_Stop, NULL, NULL, NULL, NULL, 0, 0)) != BTRVERR_SUCCESS)
    ASSERT( uErrCode == BTRVERR_RECORD_MANAGER_INACTIVE);
 #else
  m_EicBtrCall( BTRV_Stop, NULL, NULL, NULL, NULL, 0, 0);
 #endif 
}



/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*\
!!!!!!!!!!!!! CBtrvFile::Reset() !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!                                                                              !
!   Cette procédure permet de terminer toutes les sessions du MKDE.            !
\*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
void __fastcall CBtrvFile::Reset( void)
{
 if (!m_EicBtrCall)
  return;
 #ifdef _DEBUG
  unsigned uErrCode; // Code erreur

  if( ( uErrCode = m_EicBtrCall( BTRV_Reset, NULL, NULL, NULL, NULL, 0, 0)) != BTRVERR_SUCCESS)
    ASSERT( uErrCode == BTRVERR_RECORD_MANAGER_INACTIVE);
 #else
  m_EicBtrCall( BTRV_Reset, NULL, NULL, NULL, NULL, 0, 0);
 #endif  
}



/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*\
!!!!!!!!!!!!! CBtrvFile::GetVersion() *!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!                                                                              !
!   Cette fonction permet d'obtenir une version "lisible" du MKDE.             !
!                                                                              !
! Paramètres :                                                                 !
!   eVersionID : Une valeur BTRV_VERSION_* qui indqiue quelle version obtenir. !
!                                                                              !
! Retour :                                                                     !
!   La version demandée sous forme lisible.                                    !
\*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
AnsiString __fastcall CBtrvFile::GetVersion( enum BTRV_VERSION_ID eVersionID /* = BTRV_VERSION_LOCAL_MKDE */)
{
 #pragma pack( 1)
 typedef struct tagBTRV_VERSION_INFO {
   unsigned short ushVersion;
   unsigned short ushRevision;
   unsigned char  cMKDEID;     // MicroKernel Database Engine ID
 } BTRV_VERSION_INFO;
 #pragma pack()

 const char*        pcszMKDEName;   // Nom lisible d'un MKDE (à partir d'un ID MKDE)
 BTRV_VERSION_INFO  verAllMKDE[ 3]; // Version de tous les MKDE accessibles
 BTRV_VERSION_INFO* pver;           // La version d'un MKDE particulier
 char               szVer[ 40];     // Buffer de conversion de la version
 unsigned long      nSizeOf;        // Une taille
 unsigned           uErrCode;       // Code erreur

 ASSERT(eVersionID >= 0);
 ASSERT(eVersionID < ARRAYSIZE( verAllMKDE));

 nSizeOf = sizeof( verAllMKDE);
 InitBtrv32();
 if( ( uErrCode = m_EicBtrCall( BTRV_Ver, NULL, pver = verAllMKDE, &nSizeOf, NULL, 0, 0)) != BTRVERR_SUCCESS)
 { // Lecture de version impossible
   sprintf( szVer, "Erreur BTrieve n° %u", uErrCode);
   goto Fin;
 }
 // Formatage de la version souhaitée //
 if( ( eVersionID > 0) && ( eVersionID < ARRAYSIZE( verAllMKDE)))
   pver += eVersionID;
 switch( pver->cMKDEID)
 { case 'S' : pcszMKDEName = "Server-based";        break;
   case 'N' : pcszMKDEName = "Requester";           break;
   case 'D' : pcszMKDEName = "DOS MKDE";            break;
   case 'P' : pcszMKDEName = "OS/2 MKDE";           break;
   case 'W' : pcszMKDEName = "Windows MKDE";        break;
   default  : pcszMKDEName = "Système inconnu !!!"; break;
 }
 sprintf( szVer, pver->ushVersion ? "%u.%u %c (%s)" : "Non installé",
                 (unsigned)pver->ushVersion, (unsigned)pver->ushRevision, pver->cMKDEID,
                 pcszMKDEName);
Fin:
 ASSERT( *szVer);
 ASSERT_VALID_STRING( szVer);

 return AnsiString( szVer);
}



/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*\
!!!!!!!!!!!!! CBtrvFile::IsEmpty() !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!                                                                              !
!   Cette fonction permet de savoir si un fichier BTrieve est vide ou non.     !
!                                                                              !
! Paramétres :                                                                 !
!   tag              : Tag de l'appelant                                       !
!   strShortFileName : Nom court du fichier à tester                           !
!                                                                              !
! Retour :                                                                     !
!   TRUE si le fichier est bien un fichier BTrieve et qu'il ne contient aucun  !
! enregistrement; FALSE sinon (i.e. s'il y a erreur d'ouverture ou que le      !
! fichier contient des enregistrements.                                        !
\*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
bool __fastcall CBtrvFile::IsEmpty( EICTag            tag,
                                    const AnsiString& strShortFileName)
{
 CBtrvFile btrvfile; // Fichier BTrieve
 bool      bIsEmpty; // TRUE si le fichier est bien un fchier BTrieve et qu'il ne contient aucun enregistrement

 //ASSERT_FILENAME( strShortFileName);
 //Assert mis en commentaire pour le cas d'un fichier renommer, genre REVAOTVTOLD.dat, qui provoque un assert pour rien
 bIsEmpty = false;
 // Lecture du nb d'enregistrements //
 try {
   btrvfile.Open( TAG( 30), BTRV_R, 4096, strShortFileName);
   if( btrvfile.NbEnreg == 0)
     bIsEmpty = true;
 } catch( EUser& e) {
   // Pb d'accès au fichier (il n'est pas BTrieve, n'existe pas ou ne peut être lu)
   // => On ignore l'erreur
 } catch( Exception& e) {
   // Autre erreur
   // => On la relève avec l'origine
   throw EUser( tag, e);
 }
 return bIsEmpty;
}



/******************************************************************************\
************* CBtrvFile::Call() ************************************************
********************************************************************************
*                                                                              *
*   Cette fonction permet d'effectuer un appel BTrieve basique avec une gestion*
* personnalisée du code erreur.                                                *
*                                                                              *
* Paramètres :                                                                 *
*   tag          : Tag de l'opération                                          *
*   eOperation   : Code d'opération BTrieve (une valeur BTRV_*)                *
*   pvDataBuffer : Buffer de données (en lecture/écriture)                     *
*   pvKeyBuffer  : Buffer de clé     (en lecture/écriture)                     *
*   eKeyID       : N° de la clé pour l'opération à réaliser                    *
*   uNbErrCodes  : Nombre de codes erreur gérés par la fonction (<0=tous)      *
*   ...          : Codes erreur autorisés par la fonction (si l'appel BTrieve  *
*                  génère une erreur qui figure dans cette liste, aucune       *
*                  exception n'est levée et la fonction retourne le code erreur*
*                  en question; sinon, une exception EUser est levée).         *
*                                                                              *
* Retour :                                                                     *
*   BTRVERR_SUCCESS ou une des valeurs BTRVERR_* de la liste des erreurs       *
* autorisées.                                                                  *
\******************************************************************************/
unsigned __cdecl CBtrvFile::Call( EICTag tag,
                                  WORD   eOperation,
                                  void*  pvDataBuffer,
                                  void*  pvKeyBuffer,
                                  WORD   eKeyID,
                                  int    uNbErrCodes,  /* = 0 ( < 0 pour tous ) */
                                  ...)
{
 unsigned uErrCode;    // Code de retour de la fonction
 va_list  lstErrCodes; // Liste des codes erreur autorisés

 #ifdef _DEBUG
  unsigned long nSizeOfRecord = m_nSizeOfRecord;
 #endif

 ASSERT( pvDataBuffer);
 ASSERT( ( pvDataBuffer == sm_pvDummy) ||
         ( !::IsBadReadPtr( pvDataBuffer, nSizeOfRecord) &&
           !::IsBadWritePtr( pvDataBuffer, nSizeOfRecord)));
 ASSERT( (  pvKeyBuffer && ( eKeyID != K_CURRENT)) ||
         ( !pvKeyBuffer && ( eKeyID == K_CURRENT)));

 m_StatusErreur = 0;

 void* pvKey = pvKeyBuffer;
 if( !pvKeyBuffer && ( eKeyID == K_CURRENT))
 {
 	pvKey = malloc( MAX_KEY_SIZE);
 }
 // Exécution de l'opération //
 uErrCode = m_EicBtrCall( eOperation, m_pos,
                     pvDataBuffer, &m_nSizeOfRecord,
                     pvKey, MAX_KEY_SIZE, eKeyID);

 if( !pvKeyBuffer && ( eKeyID == K_CURRENT))
 {
 	free( pvKey);
 }

 ASSERT_DUMMY(); // Car sm_pvDummy peut être passé à la place d'un pointeur
// ASSERT( nSizeOfRecord == m_nSizeOfRecord);

 // Traitement de l'erreur //
 if( ( uErrCode != BTRVERR_SUCCESS) && ( uNbErrCodes >= 0))
 { // L'appelant veut filtrer certains codes d'erreur
   va_start( lstErrCodes, uNbErrCodes);
   while( uNbErrCodes--)
     if( uErrCode == va_arg( lstErrCodes, unsigned))
       // Ce code erreur est supporté par l'appelant
       return uErrCode;

   // Le code erreur retourné n'est pas filtré par l'appelant
   // => Levée d'exception
   ThrowUserError( tag, eOperation, eKeyID, uErrCode);
 }
 SET_LAST_KEY( eKeyID);
 return uErrCode;
} /* CBtrvFile::Call() */



/******************************************************************************\
************* CBtrvFile::ThrowUserError() **************************************
********************************************************************************
*                                                                              *
*   Cette procédure permet de lever une exception EUser avec des paramètres qui*
* permettent de conaître l'origine et la cause - au sens BTrieve - de l'erreur *
* qui est arrivée sur le fichier.                                              *
*                                                                              *
* Paramètres :                                                                 *
*   tag        : Tag de l'opération qui a provoqué l'erreur                    *
*   eOperation : Code d'opération qui a provoqué l'erreur (une valeur BTRV_*)  *
*   eKeyID     : N° de la clé utilisée dans l'opération qui a provoqué l'erreur*
*   uErrCode   : Code erreur BTrieve (une valeur d'erreur BTRVERR_*)           *
\******************************************************************************/
void __fastcall CBtrvFile::ThrowUserError( EICTag   tag,
                                           WORD     eOperation,
                                           WORD     eKeyID,
                                           unsigned uErrCode)
const
{
  m_StatusErreur = uErrCode;
  throw EUser( tag, EICFormat(
                    "Une erreur est survenue lors d'un accès à un fichier BTrieve.\n\nParamètres :\n"
                    "\tOrigine\t : %u-%u\n"
                    "\tStatut\t : %u\n"
                    "\tOpération\t : %u\n"
                    "\tLongueur\t : %lu\n"
                    "\tClé\t : %u\n"
                    "\tFichier\t : \"%s\"",
                    TAG_MODULE(tag), TAG_TAG(tag),
                    uErrCode,
                    eOperation,
                    m_nSizeOfRecord,
                    (unsigned)eKeyID,
                    m_strShortFileName.c_str()));
}



/******************************************************************************\
************* CBtrvFile::Create() **********************************************
********************************************************************************
*                                                                              *
*   Cette procédure permet de créer un fichier BTrieve.                        *
*                                                                              *
* Paramètres :                                                                 *
*   tag                 : Tag de l'opération                                   *
*   strNewShortFileName : Nom (court) du fichier à créer (ce nom devient le    *
*                         nom de fichier de l'instance).                       *
*   pcfs                : Spécifications de création du fichier.               *
*   nSizeOfFileSpec     : Taille des spécifications de création du fichier     *
*                         (obtenue aisément avec la macro BTRV_SIZEOF()).      *
*   bOverwriteIfExistYet: TRUE si la fonction peut écraser le fichier s'il est *
*                         déjà existant (sinon, une exception EUser est levée).*
*                                                                              *
* Note : Le nom du fichier étant stocké dans l'instance, il peut être omis dans*
*        le prochain appel à Open().                                           *
\******************************************************************************/
bool __fastcall CBtrvFile::Create( EICTag                tag,
                                   const AnsiString&     strNewShortFileName,
                                   const BTRV_FILE_SPEC* pcfs,
                                   size_t                nSizeOfFileSpec,
                                   enum ACTION_CREATE    eAction /* = ERROR_IF_FILE_EXIST */)
{
 unsigned uErrCode; // Code erreur
 char     szShortPathNameForUseLongPathName[ MAX_PATH];

 // ASSERT_FILENAME( strNewShortFileName); N'importe quoi car le fichier n'existe pas forcément
 ASSERT(pcfs);
 ASSERT(nSizeOfFileSpec > BTRV_SIZEOF(0));
 #pragma option -w-rch // Warning: "Unreachable code."
  ASSERT(sizeof(nSizeOfFileSpec) == sizeof(unsigned long));
 #pragma option -w.rch

  m_StatusErreur = 0;
 // Création du nouveau fichier //
  if( ::GetShortPathName( strNewShortFileName.c_str(), szShortPathNameForUseLongPathName, MAX_PATH))
    m_strShortFileName = AnsiString( szShortPathNameForUseLongPathName);       //On transforme en nom court
  else                                           //Il s'agit d'un nouveau fichier
    m_strShortFileName = strNewShortFileName;    //On suppose que le nom est court
 switch( uErrCode = m_EicBtrCall( BTRV_Create, sm_pvDummy,
                             (void*)pcfs, (unsigned long*)&nSizeOfFileSpec,
                             m_strShortFileName.c_str(),
                             0, (BTI_CHAR)( (eAction == OVERWRITE_IF_FILE_EXIST) ? 0x00 : 0xFF)))
 { case BTRVERR_SUCCESS        :
     return true;

   case BTRVERR_FILE_ALREADY_EXIST :
     if( eAction != ERROR_IF_FILE_EXIST)
     { /* Fichier déjà existant */
        if( ( eAction == OVERWRITE_IF_FILE_EXIST) ||
            ( eAction == NO_ERROR_NO_OVERWRITE_IF_FILE_EXIST))
          return true;
       break;
     }
     // !!! ON CONTINUE SUR LE CAS SUIVANT !!!

   default                  :
     ThrowUserError( tag, BTRV_Create, eAction, uErrCode);
     break;
 }
 return false;
} /* CBtrvFile::Create() */



/******************************************************************************\
************* CBtrvFile::Open() ************************************************
********************************************************************************
*                                                                              *
*   Cette procédure permet d'ouvrir un fichier BTrieve.                        *
*                                                                              *
* Paramètres :                                                                 *
*   tag                : Tag de l'opération                                    *
*   eOpenMode          : Mode d'ouverture du fichier (BTRV_R ou BTRV_RW)       *
*   nSizeOfRecord      : Taille attendue des enregistrements du fichier.       *
*   strShortFileName   : Nom du fichier à ouvrir (EmtyStr=dernier nom utilisé) *
*   bNoErrorIfNotFound : FALSE pour lever une exception EUser si le fichier à  *
*                        ouvrir n'existe; TRUE pour ne pas ouvrir le fichier   *
*                        s'il n'existe pas.                                    *
*                                                                              *
* Retour :                                                                     *
*   TRUE si le fichier a bien été ouvert; FALSE sinon (cette valeur ne peut    *
* être retournée que si bNoErrorIfNotFound vaut TRUE).                         *
\******************************************************************************/
bool __fastcall CBtrvFile::Open( EICTag              tag,
                                 enum BTRV_OPEN_MODE eOpenMode,
                                 size_t              nSizeOfRecord,
                                 const AnsiString&   strShortFileName,  /* = EmptyStr */
                                 bool                bNoErrorIfNotFound /* = false */)
{
 unsigned  uErrCode; // Code erreur
 char      szShortPathNameForUseLongPathName[ MAX_PATH];

 ASSERT( nSizeOfRecord);

 m_StatusErreur = 0;
 // Conversion du nom de fichier //
      if (  strShortFileName.IsEmpty() && !FileExists(m_strShortFileName)) return false;  //Le fichier n'existe pas, on ne peut pas l'ouvrir, c'est pas la peine d'aller plus loin
 else if ( !strShortFileName.IsEmpty() && !FileExists(  strShortFileName)) return false;


 if( !strShortFileName.IsEmpty()) {
   ::GetShortPathName( strShortFileName.c_str(), szShortPathNameForUseLongPathName, MAX_PATH);
   m_strShortFileName = AnsiString( szShortPathNameForUseLongPathName);    // Il s'agit d'un nouveau fichier
 }

 ASSERT_FILENAME( m_strShortFileName);

 // Ouverture du nouveau fichier //
 switch( uErrCode = m_EicBtrCall( BTRV_Open, m_pos, sm_pvDummy, (unsigned long*)sm_pvDummy, m_strShortFileName.c_str(), 0, eOpenMode))
 { case BTRVERR_SUCCESS        :
     ASSERT_DUMMY();
     break;

   case BTRVERR_FILE_NOT_FOUND :
     if( bNoErrorIfNotFound)
     { /* Fichier non trouvé */
       ASSERT_DUMMY();
       return false;
     }
     // !!! ON CONTINUE SUR LE CAS SUIVANT !!!

   default                     :
     ASSERT_DUMMY();
     ThrowUserError( tag, BTRV_Open, eOpenMode, uErrCode);
     break;
 }
 // Stockage des attributs du fichier //
 m_nSizeOfRecord = nSizeOfRecord;
 SET_LAST_KEY( K_UNKNOWN);
 return true;
} /* CBtrvFile::Open() */



/******************************************************************************\
************* CBtrvFile::Close() ***********************************************
********************************************************************************
*                                                                              *
*   Cette procédure permet de fermer le fichier.                               *
*                                                                              *
* Paramètres :                                                                 *
*   tag : Tag de l'opération                                                   *
*                                                                              *
* Note : La fermeture d'un fichier non ouvert ne produit aucune erreur.        *
\******************************************************************************/
void __fastcall CBtrvFile::Close( EICTag tag)
{
 if( m_nSizeOfRecord)
 {
    ASSERT( IsOpened);

   Call( tag, BTRV_Close, sm_pvDummy, sm_pvDummy, 0);
   // RAZ des attributs du fichier //
   m_nSizeOfRecord = 0;
   SET_LAST_KEY( K_UNKNOWN);
 }

 ASSERT(!IsOpened);
 ASSERT(IS_LAST_KEY( K_UNKNOWN));
}



/******************************************************************************\
************* CBtrvFile::StepNext() ********************************************
********************************************************************************
*                                                                              *
*   Cette fonction permet d'accéder à l'enregistrement physique suivant du     *
* fichier.                                                                     *
*                                                                              *
* Paramètres :                                                                 *
*   tag      : Tag de l'opération                                              *
*   pvBuffer : Buffer de stockage de l'enregistrement lu.                      *
*                                                                              *
* Retour :                                                                     *
*   TRUE si l'enregistrement physique suivant a bien été lu; FALSE s'il n'y a  *
* plus d'enregistrement suivant (i.e. on est à la fin du fichier).             *
*                                                                              *
* Note : Si cette opération est celle qui suit l'opération Open(),             *
*        l'enregistrement lu est en fait le 1er enreg. physique du fichier.    *
\******************************************************************************/
bool __fastcall CBtrvFile::StepNext( EICTag tag,
                                     void*  pvBuffer)
{
 ASSERT(IsOpened);
 ASSERT(!::IsBadWritePtr( pvBuffer, m_nSizeOfRecord));

 SET_LAST_KEY( K_UNKNOWN);
 // Lecture de l'enregistrement chronologique suivant //
 return Call( tag, BTRV_StepNext, pvBuffer, sm_pvDummy, 0, 1, BTRVERR_EOF) == BTRVERR_SUCCESS;
}



/******************************************************************************\
************* CBtrvFile::DelCurrent() ******************************************
********************************************************************************
*                                                                              *
*   Cette procédure permet de détruire l'enregistrement courant.               *
*                                                                              *
* Paramètres :                                                                 *
*   tag : Tag de l'opération                                                   *
*                                                                              *
* Attention : Cette opération détruit la clé logique courante.                 *
\******************************************************************************/
void __fastcall CBtrvFile::DelCurrent( EICTag tag)
{
 ASSERT( IsOpened);

 Call( tag, BTRV_Delete, sm_pvDummy, sm_pvDummy, 0);
}



/******************************************************************************\
************* CBtrvFile::GetFirst() ********************************************
********************************************************************************
*                                                                              *
*   Cette fonction permet de lire le 1er enregistrement qui correspond au(x)   *
* critère(s) d'une clé.                                                        *
*                                                                              *
* Paramètres :                                                                 *
*   tag       : Tag de l'opération                                             *
*   pvBuffer  : Buffer de retour de l'enregistrement lu.                       *
*   pvKey     : Buffer de stockage des critères de la clé                      *
*   eNewKeyID : Clé logique selon laquelle lire le 1er enregistrement.         *
*                                                                              *
* Retour :                                                                     *
*   TRUE si un enregistrement qui satisfait au(x) critère(s) de la clé a été   *
* trouvé; FALSE sinon (il n'existe pas d'enr. qui satisfasse au(x) critère(s)).*
*                                                                              *
* Note : La clé logique passée en paramètre devient la clé logique courante    *
\******************************************************************************/
bool __fastcall CBtrvFile::GetFirst(EICTag tag,void *pvBuffer,void *pvKey,WORD eNewKeyID)
{
 ASSERT( IsOpened);
 ASSERT(!::IsBadWritePtr(pvBuffer,m_nSizeOfRecord));
 ASSERT(pvKey);

 // Lecture du 1er enregistrement de la clé //
 // La lecture est chronologique au sein d'enregistrements qui ont une même valeur de clé
 if( Call( tag, BTRV_GetFirst, pvBuffer, pvKey, eNewKeyID, 1, BTRVERR_EOF) == BTRVERR_SUCCESS)
 { // Lecture Ok
   //SET_LAST_KEY( eNewKeyID); c'est fait ds le ::Call(...)
   return true;
 }
 SET_LAST_KEY(K_UNKNOWN);
 return false;
}



/******************************************************************************\
************* CBtrvFile::GetNext() *********************************************
********************************************************************************
*                                                                              *
*   Cette fonction permet de lire le l'enregistrement suivant selon la clé     *
* indiquée.                                                                    *
*                                                                              *
* Paramètres :                                                                 *
*   tag            : Tag de l'opération                                        *
*   pvBuffer       : Buffer de retour de l'enregistrement lu.                  *
*   pvKey          : Buffer de retour de la valeur de clé lue.                 *
*   ePreviousKeyID : Clé logique selon laquelle lire l'enregistrement suivant  *
*                    (cette clé doit être la clé logique courante sous peine   *
*                    de levée d'une exception).                                *
*                                                                              *
* Retour :                                                                     *
*   TRUE si un enregistrement suivant à été trouvé selon l'ordre de la clé;    *
* FALSE sinon (i.e. aucun enregistrement suivant n'existe selon la clé).       *
\******************************************************************************/
bool __fastcall CBtrvFile::GetNext( EICTag tag,
                                    void*  pvBuffer,
                                    void*  pvKey,
                                    WORD   ePreviousKeyID)
{
 ASSERT(IsOpened);
 ASSERT(!::IsBadWritePtr( pvBuffer, m_nSizeOfRecord));
 ASSERT(pvKey);
 ASSERT(IS_LAST_KEY( ePreviousKeyID));

 // Lecture de l'enregistrement suivant selon la clé //
 // La lecture est chronologique au sein d'enregistrements qui ont une même valeur de clé
 return Call( tag, BTRV_GetNext, pvBuffer, pvKey, ePreviousKeyID, 1, BTRVERR_EOF) == BTRVERR_SUCCESS;
}



/******************************************************************************\
************* CBtrvFile::GetEQ() ***********************************************
********************************************************************************
*                                                                              *
*   Cette fonction permet de lire un enregistrement qui satisfait à la(aux)    *
* valeur(s) d'une clé.                                                         *
*                                                                              *
* Paramètres :                                                                 *
*   tag       : Tag de l'opération                                             *
*   pvBuffer  : Buffer de retour de l'enregistrement lu.                       *
*   pcvKey    : Valeur(s) de la clé de recherche.                              *
*   eNewKeyID : Clé logique de recherche.                                      *
*                                                                              *
* Retour :                                                                     *
*   TRUE si un enregistrement a été trouvé selon la valeur de clé spécifiée;   *
* FALSE sinon.                                                                 *
*                                                                              *
* Note : La clé logique passée en paramètre devient la clé logique courante    *
\******************************************************************************/
bool __fastcall CBtrvFile::GetEQ( EICTag      tag,
                                  void*       pvBuffer,
                                  const void* pcvKey,
                                  WORD        eNewKeyID)
{
 ASSERT( IsOpened);
 ASSERT(!::IsBadWritePtr( pvBuffer, m_nSizeOfRecord));
 ASSERT(pcvKey);

 // Lecture du 1er enregistrement qui a la valeur de clé demandée //
 // La lecture est chronologique au sein d'enregistrements qui ont une même valeur de clé
 if( Call( tag, BTRV_GetEQ, pvBuffer, (void*)pcvKey, eNewKeyID, 1, BTRVERR_KEY_NOT_FOUND) == BTRVERR_SUCCESS)
 { // Enregistrement trouvé
   //SET_LAST_KEY( eNewKeyID); C'est fait ds le ::Call
   return true;
 }
 return false;
}


/******************************************************************************\
************* CBtrvFile::GetGTEQ() *********************************************
********************************************************************************
*                                                                              *
*   Cette fonction permet de lire le premier enregistrement qui satisfait à la(aux)    *
* valeur(s) d'une clé.                                                         *
*                                                                              *
* Paramètres :                                                                 *
*   tag       : Tag de l'opération                                             *
*   pvBuffer  : Buffer de retour de l'enregistrement lu.                       *
*   pcvKey    : Valeur(s) de la clé de recherche.                              *
*   eNewKeyID : Clé logique de recherche.                                      *
*                                                                              *
* Retour :                                                                     *
*   TRUE si un enregistrement a été trouvé selon la valeur de clé spécifiée;   *
* FALSE sinon.                                                                 *
*                                                                              *
* Note : La clé logique passée en paramètre devient la clé logique courante    *
\******************************************************************************/
bool __fastcall CBtrvFile::GetGTEQ( EICTag      tag,
                                    void*       pvBuffer,
                                    void*       pcvKey,
                                    WORD        eNewKeyID)
{
 ASSERT( IsOpened);
 ASSERT(!::IsBadWritePtr( pvBuffer, m_nSizeOfRecord));
 ASSERT(pcvKey);

 // Lecture du 1er enregistrement qui a la valeur de clé demandée //
 // La lecture est chronologique au sein d'enregistrements qui ont une même valeur de clé
 if( Call( tag, BTRV_GetGTEQ, pvBuffer, pcvKey, eNewKeyID, 1, BTRVERR_EOF) == BTRVERR_SUCCESS)
 { // Enregistrement trouvé
   //SET_LAST_KEY( eNewKeyID); C'est fait ds le ::Call
   return true;
 }
 return false;
}



bool __fastcall CBtrvFile::GetGT( EICTag      tag,
                                  void*       pvBuffer,
                                  const void* pcvKey,
                                  WORD        eNewKeyID)
{
 ASSERT( IsOpened);
 ASSERT(!::IsBadWritePtr( pvBuffer, m_nSizeOfRecord));
 ASSERT(pcvKey);

 // Lecture du 1er enregistrement qui a la valeur de clé demandée //
 // La lecture est chronologique au sein d'enregistrements qui ont une même valeur de clé
 if( Call( tag, BTRV_GetGT, pvBuffer, (void*)pcvKey, eNewKeyID, 1, BTRVERR_EOF) == BTRVERR_SUCCESS)
 { // Enregistrement trouvé
   //SET_LAST_KEY( eNewKeyID); C'est fait ds le ::Call
   return true;
 }
 return false;
}



/******************************************************************************\
************* CBtrvFile::InsertNew() *******************************************
********************************************************************************
*                                                                              *
*   Cette procédure permet d'insérer un nouvel enregistrement dans le fichier. *
*                                                                              *
* Paramètres :                                                                 *
*   tag       : Tag de l'opération                                             *
*   pcvBuffer : Enregistrement à insérer dans le fichier.                      *
*   pvKey     : Valeur prise par la clé d'insertion (NULL pour ignorer)        *
*   eNewKeyID : Nouvelle clé logique (K_CURRENT pour ne pas changer)           *
*                                                                              *
* Note : La clé logique passée en paramètre devient la clé logique courante    *
\******************************************************************************/
void __fastcall CBtrvFile::InsertNew( EICTag      tag,
                                      const void* pcvBuffer,
                                      void*       pvKey,    /* = NULL */
                                      WORD        eNewKeyID /* = K_CURRENT */)
{
 ASSERT(IsOpened);
 ASSERT(!::IsBadReadPtr( pcvBuffer, m_nSizeOfRecord));
 ASSERT( ( !pvKey && ( eNewKeyID == K_CURRENT)) ||
         (  pvKey && ( eNewKeyID != K_CURRENT)));

 // Insertion du nouvel enregistrement //
 Call( tag, BTRV_Insert, (void*)pcvBuffer, pvKey, eNewKeyID);
 //SET_LAST_KEY( eNewKeyID); C'est fait ds le ::Call
}



/******************************************************************************\
************* CBtrvFile::UpdateCurrent() ***************************************
********************************************************************************
*                                                                              *
*   Cette procédure permet de mettre à jour l'enregistrmeent courant.          *
*                                                                              *
* Paramètres :                                                                 *
*   tag            : Tag de l'opération                                        *
*   pcvBuffer      : Nouvelle valeur de l'enregistrement courant.              *
*   pvKey          : Valeur prise par la clé d'insertion (NULL pour ignorer)   *
*   ePreviousKeyID : Clé logique selon laquelle MAJ l'enregistrement courant   *
*                    (cette clé doit être la clé logique courante sous peine   *
*                    de levée d'une exception).                                *
\******************************************************************************/
void __fastcall CBtrvFile::UpdateCurrent( EICTag      tag,
                                          const void* pcvBuffer,
                                          void*       pvKey,         /* = NULL */
                                          WORD        ePreviousKeyID /* = K_CURRENT */)
{
 ASSERT(IsOpened);
 ASSERT(!::IsBadReadPtr(pcvBuffer,m_nSizeOfRecord));
 ASSERT((!pvKey && (ePreviousKeyID == K_CURRENT)) ||
        (pvKey && (ePreviousKeyID != K_CURRENT)));

 // MAJ de l'enregistrement courant //
 Call( tag, BTRV_Update, (void*)pcvBuffer, pvKey, ePreviousKeyID);
} 


/******************************************************************************\
************* CBtrvFile::GetPosition() *****************************************
********************************************************************************
*                                                                              *
*   Cette procédure permet de récupérer l'enregistrmeent courant.              *
*                                                                              *
* Paramètres :                                                                 *
*   tag            : Tag de l'opération                                        *
\******************************************************************************/
long __fastcall CBtrvFile::GetPosition( EICTag  tag)
{
 ASSERT( IsOpened);

 long lCurrentPos = 0L;
 int  nTmp = m_nSizeOfRecord;

 m_nSizeOfRecord = sizeof( lCurrentPos);
 Call( tag, BTRV_GetPos, (void*)&lCurrentPos, sm_pvDummy, 0, 1, BTRVERR_INVALID_POSITION);
 m_nSizeOfRecord = nTmp;

 return lCurrentPos;
}



/******************************************************************************\
************* CBtrvFile::GetDirect() *******************************************
********************************************************************************
*                                                                              *
*   Cette procédure permet de se repositionner à la position indiquée.         *
*                                                                              *
* Paramètres :                                                                 *
*   tag       : Tag de l'opération                                             *
*   pvBuffer  : Buffer de retour de l'enregistrement lu.                       *
*   pcvKey    : Valeur(s) de la clé de recherche.                              *
*   eNewKeyID : Clé logique de recherche.                                      *
*   lPos      : Position à rechercher.                                         *
\******************************************************************************/
bool __fastcall CBtrvFile::GetDirect( EICTag tag, void* pvBuffer, void* pcvKey, WORD eNewKeyID, long lPos)
{
 ASSERT(IsOpened);
 ASSERT(!::IsBadWritePtr( pvBuffer, m_nSizeOfRecord));
 ASSERT(pcvKey);

 *(long*)pvBuffer = lPos;
 if( Call( tag, BTRV_GetDirect, pvBuffer, pcvKey, eNewKeyID, 1, BTRVERR_INVALID_RECOD_ADDRESS) == BTRVERR_SUCCESS)
 { // Enregistrement trouvé
   //SET_LAST_KEY( eNewKeyID); C'est fait ds le ::Call
   return true;
 }
 return false;
}



void __fastcall CBtrvFile::Stat( EICTag tag,BTRV_FILE_SPEC* pcfs)
{
 unsigned long  nSizeOf;                     // Taille de la structure
 unsigned       uErrCode;                    // Code erreur
 char           szExtendedFileFileName[ 64]; // Nom du fichier étendu associé

 ASSERT( IsOpened);

 m_StatusErreur = 0;
 ////////////////////////////////////////////////////////////
 // Lecture du nombre d'enregistrements actuels du fichier //
 ////////////////////////////////////////////////////////////
 nSizeOf = sizeof( *pcfs);
 switch( uErrCode = m_EicBtrCall( BTRV_Stat, (void*)m_pos, pcfs, &nSizeOf, szExtendedFileFileName, sizeof( szExtendedFileFileName), 0))
 { case BTRVERR_DATA_BUFFER_LENGTH :
   case BTRVERR_SUCCESS            : break;
   default                         : ThrowUserError( TAG( 21), BTRV_Stat, 0, uErrCode);
 }
}



int __fastcall CBtrvFile::GetRecordCount()
{
  BTRV_FILE_SPEC pcfs;

  ASSERT(IsOpened);

  Stat(TAGL,&pcfs);
  return pcfs.dwNbRecords;   
}


void __fastcall CBtrvFile::InitBtrv32()
{
 if (!hBtr)
 {
   if((hBtr = LoadLibrary("FBTRV32.dll")) == NULL)
     throw EAbort( "Impossible de charger FBTRV32.dll." );
   m_EicBtrCall = (BTRCALLFCT)GetProcAddress(hBtr, "BTRCALL" );
 }
}
